package com.buhler.iot;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.setting.dialect.Props;
import com.buhler.iot.entity.SchemaEntity;
import com.buhler.iot.entity.ScriptEntity;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import com.xxdb.data.*;
import com.xxdb.data.Vector;


import java.time.LocalDateTime;
import java.util.*;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 脚本和脚本数据生成器
 *
 */
public class ScriptGenerator {
    private String databaseName;
    // 每张表的数据行数
    private  int size;

    private Map<String, List<SchemaEntity>> schemaMap;
    private List<String> tables;
    private String[] productCodes;

    private Long[] stCodes ={1L,2L,3L,4L,7L,8L,9L,11L,16L,32L, 259L, 513L};

    private List<String> columnNames ;

    public ScriptGenerator(int size){
        this.size  = size;
        init();
    }

    public void init(){
        ExcelReader reader = ExcelUtil.getReader("data.xlsx");
        List<SchemaEntity> schemaEntities = reader.readAll(SchemaEntity.class);
        reader.close();
        this.schemaMap = schemaEntities.stream().collect(Collectors.groupingBy(SchemaEntity::getTableName));
        this.tables  = Lists.newArrayList(schemaMap.keySet());

        Props prop = new Props("config.txt");
        this.databaseName = prop.getStr("database_name");
        this.productCodes = prop.getStr("productIdent").split(",");
        String columnName = prop.getStr("column_name");
        this.columnNames= Arrays.asList(columnName.split(","));
    }

    /**
     * 主要生成策略：
     * 通过查表法，随机取出特定行数的数据
     * 但是Float类型的 value 不是查表，直接随机生成
     * @return
     */
    public Set<ScriptEntity> generate(){
        Set<ScriptEntity> sets = Sets.newHashSet();
        for (String tableName: tables) {
            String script = String.format("tableInsert{loadTable('%s','%s')}",this.databaseName,tableName);
            ScriptEntity scriptEntity = new ScriptEntity();
            scriptEntity.setTable(createBasicTable(tableName));
            scriptEntity.setTableName(tableName);
            scriptEntity.setScript(script);
            sets.add(scriptEntity);
        }
        return sets;
    }


    private  List<SchemaEntity>  generateMain(String tableName){
        List<SchemaEntity> schemaEntities = schemaMap.get(tableName);
        int length = schemaEntities.size();
        List<SchemaEntity> ret = Lists.newArrayList();
        for (int i = 0; i < this.size; i++) {
            int index = RandomUtil.randomInt(0, length);
            ret.add(schemaEntities.get(index));
        }
        return ret;
    }

    private List<Long> generateLong(){
        List<Long> ret = Lists.newArrayList();
        int length = this.stCodes.length;
        for (int i = 0; i < this.size; i++) {
            int index = RandomUtil.randomInt(0, length);
            ret.add(this.stCodes[index]);
        }
        return ret;
    }

    private List<Float> generateFloat(){
        List<Float> ret = Lists.newArrayList();
        for (int i = 0; i < this.size; i++) {
            Double value = RandomUtil.randomDouble(0, 1000.0d);
            ret.add(value.floatValue());
        }
        return ret;
    }

    private List<String> generateString(){
        List<String> ret = Lists.newArrayList();
        int length = productCodes.length;
        for (int i = 0; i < this.size; i++) {
            int index = RandomUtil.randomInt(0, length);
            ret.add(productCodes[index]);
        }
        return ret;
    }

    private List<Long> generateTime(){
        List<Long> ret = Lists.newArrayList();

        long now = Utils.countDTNanoseconds(LocalDateTime.now());
        for (int i = 0; i < this.size; i++) {
            now=now+50L;
            ret.add(now);
        }
        return ret;
    }


    private BasicTable createBasicTable(String tableName) {
        List<Long> timestamps = generateTime();
        BasicNanoTimestampVector timeColumn = new BasicNanoTimestampVector(timestamps);
        List<Float> coefficientValues= Lists.newArrayList();
        List<Float> coefficientTextValues= Lists.newArrayList();
        List<Integer> decimalPlacesValues= Lists.newArrayList();
        List<String> deviceIdValues = Lists.newArrayList();
        List<String> displayNameValues = Lists.newArrayList();
        List<String> displayTypeValues = Lists.newArrayList();
        List<Long> ids = Lists.newArrayList();
        List<String> labels = Lists.newArrayList();
        Vector originValueVector = null;
        List<String> types = Lists.newArrayList();
        List<String> typeNames = Lists.newArrayList();
        Vector valueVector = null;
        List<SchemaEntity> schemaEntities = this.generateMain(tableName);
        for (SchemaEntity schemaEntity : schemaEntities) {
            coefficientValues.add(schemaEntity.getCoefficient());
            coefficientTextValues.add(schemaEntity.getCoefficientText());
            decimalPlacesValues.add(schemaEntity.getDecimalPlaces());
            deviceIdValues.add(schemaEntity.getDeviceId());
            displayNameValues.add(schemaEntity.getDisplayName());
            displayTypeValues.add(schemaEntity.getDisplayType());
            ids.add(schemaEntity.getId());
            labels.add(schemaEntity.getLabel());
            types.add(schemaEntity.getType());
            typeNames.add(schemaEntity.getTableName());
            switch (tableName) {
                case "Line_ProductIdent":
                    List<String> stringValues = generateString();
                    originValueVector= new BasicStringVector(stringValues);
                    valueVector= new BasicStringVector(stringValues);
                    break;
                case "Grinder_StCode":
                case "Grinder_BreakSieveAlarm":
                case "Grinder_CumulativeNormalRunHours":
                case "Extruder_StCode":
                case "Extruder_CumulativeNormalRunHours":
                case "Line_StCode":
                    List<Long> longValues = generateLong();
                    originValueVector= new BasicLongVector(longValues);
                    valueVector= new BasicLongVector(longValues);
                    break;
                default:
                    List<Float> floatValues = generateFloat();
                    originValueVector= new BasicFloatVector(floatValues);
                    valueVector= new BasicFloatVector(floatValues);
                    break;
            }
        }
        List<Vector> cols = new ArrayList<>();
        cols.add(timeColumn);
        cols.add(new BasicFloatVector(coefficientValues));
        cols.add(new BasicFloatVector(coefficientTextValues));
        cols.add(new BasicIntVector(decimalPlacesValues));
        cols.add(new BasicSymbolVector(deviceIdValues));
        cols.add(new BasicStringVector(displayNameValues));
        cols.add(new BasicStringVector(displayTypeValues));
        cols.add(new BasicLongVector(ids));
        cols.add(new BasicStringVector(labels));
        cols.add(originValueVector);
        cols.add(new BasicSymbolVector(types));
        cols.add(new BasicSymbolVector(typeNames));
        cols.add(valueVector);

        return  new BasicTable(this.columnNames, cols);
    }
}
